package network.ssl;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import tools.ConfParser;


/**
 * Traite un client sur le serveur.
 * @author Guillaume Poças
 */
public class KrakenSSLThread implements Runnable{
	
	private static final String PATH_CONF_FILE = "/etc/kraken/sslserver.conf";
	private static final String DEFAULT_PORT = "DEFAULT_PORT";
	private static final String VIDEO_PORT = "VIDEO_PORT";
	
	private Thread thread;
	private Socket socket;
	private PrintWriter out; // pour gestion du flux de sortie
	private BufferedReader in; // pour gestion du flux d'entree
	private KrakenSSLServer krakenSSLServer;
	private int numClient = 0;
	private KrakenSSLCommandInterpreter rci;
	private boolean run;
	private int port;
	private int port_cmd;
	private int port_vid;
	
	final Lock lock = new ReentrantLock();
	final Condition turn = lock.newCondition();

	
	/**
	 * Constructeur.
	 * @param s
	 * @param krakenSSLServer
	 */
	public KrakenSSLThread(Socket s, KrakenSSLServer krakenSSLServer, int port){
		this.krakenSSLServer = krakenSSLServer;
		socket = s;
		rci = null;
		run = true;
		this.port = port;
		
		ConfParser parser = new ConfParser();
		try {
			parser.parse(new File(PATH_CONF_FILE));
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		port_cmd = new Integer(parser.getValue(DEFAULT_PORT));
		port_vid = new Integer(parser.getValue(VIDEO_PORT));
		
		try{
			// fabrication d'une variable permettant l'utilisation du flux de sortie avec des string
			out = new PrintWriter(socket.getOutputStream());
			// fabrication d'une variable permettant l'utilisation du flux d'entree avec des string
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			// ajoute le flux de sortie dans la liste et recuperation de son numero
			if(port == port_cmd){
				numClient = krakenSSLServer.addClient(out,0);
			}
			else if(port == port_vid){
				numClient = krakenSSLServer.addClient(out,1);
			}
		}
		catch(IOException e){
			e.printStackTrace(); //
		}
	
		thread = new Thread(this);
		thread.start();
	}

	@Override
	public synchronized void run(){
		String message = "";
		// on indique dans la console la connection d'un nouveau client
		System.out.println(this.port+":Un nouveau client s'est connecte, no " + numClient);
		rci = new KrakenSSLCommandInterpreter(this);
		try{
			while(run){
				message = in.readLine();
				if(!message.equalsIgnoreCase("")){
					if(rci != null)	rci.interpret(message);
					message = "";
				}
			}
		}
		catch(Exception e){
			e.printStackTrace(); //
		}
		
		finally{ // finally se produira le plus souvent lors de la deconnexion du client
			try{
				System.out.println(this.port+":Le client no " + numClient + " s'est deconnecte");
				if(port == port_cmd){
					krakenSSLServer.delClient(numClient,0); 
				}
				else if(port == port_vid){
					krakenSSLServer.delClient(numClient,1);
				}
				if(!socket.isClosed())	socket.close();
			}
			catch(IOException e){
				e.printStackTrace(); //
			}
		}
	}
	
	public void setKrakenSSLCommandInterpreter(KrakenSSLCommandInterpreter rci){ this.rci = rci; }
	
	public KrakenSSLServer getKrakenSSLServer(){ return this.krakenSSLServer; }
	
	/**
	 * Envoi un message au client.
	 * @param cmd
	 */
	public void sendCommand(String cmd){
		out.println(cmd);
		System.out.println("SSLThread répond:"+cmd);
		out.flush();
	}

	public Socket getSocket() { return socket; }
	public void setSocket(Socket socket) { this.socket = socket; }
	
	public boolean getRunState(){ return this.run;	}
	public void setRunOff(){ this.run = false;	}
	
}